#include <string.h>
#include "stdinc.h"
#include "mcu.h"
#include "netutils.h"
#include <esp_efuse.h>
#include <nvs_flash.h>

/// 应用层日志标签
#define LOGTAG "SZW:MCU"


uint32_t getU32(const void *stream) {
	uint8_t *buf = (uint8_t*)stream;
	return MAKE_DWORD(buf[0], buf[1], buf[2], buf[3]);
}

uint16_t getU16(const void *stream) {
	uint8_t *buf = (uint8_t*)stream;
	return MAKE_WORD(buf[0], buf[1]);
}


/// 中断重入层级表
uint8_t _IrqReentry[IRQn_MAX] = {0};
/// 中断重入层级曾经的最大值
uint8_t _IrqReentryMax = 0;


void mcu_init() {
	// 初始化中断重入层级表
	memset(_IrqReentry, 0, sizeof(_IrqReentry));
	_IrqReentryMax = 0;
}

/**
 * 参数版 gpio_config()
 */
esp_err_t GPIO_Config(gpio_num_t pin, gpio_mode_t mode, gpio_pullup_t pull_up_en, gpio_pulldown_t pull_down_en, gpio_int_type_t intr_type) {
    gpio_config_t cfg = {
        .pin_bit_mask   = (1ULL<<pin),
        .mode           = mode,
        .pull_up_en     = pull_up_en,
        .pull_down_en   = pull_down_en,
        .intr_type      = intr_type
    };
    return gpio_config(&cfg);
}

esp_err_t GPIO_ConfigX(gpio_num_t pin, gpio_modex_t mode, gpio_int_type_t intr) {
	if(mode == GPIO_MODEX_NULL)  { return GPIO_Config(pin, GPIO_MODE_DISABLE,   GPIO_PULLUP_DISABLE, GPIO_PULLDOWN_DISABLE, intr); }
	if(mode == GPIO_MODEX_IPU)   { return GPIO_Config(pin, GPIO_MODE_INPUT,     GPIO_PULLUP_ENABLE,  GPIO_PULLDOWN_DISABLE, intr); }
	if(mode == GPIO_MODEX_IPD)   { return GPIO_Config(pin, GPIO_MODE_INPUT,     GPIO_PULLUP_DISABLE, GPIO_PULLDOWN_ENABLE,  intr); }
	if(mode == GPIO_MODEX_OPPL)  { return GPIO_Config(pin, GPIO_MODE_OUTPUT,    GPIO_PULLUP_ENABLE,  GPIO_PULLDOWN_ENABLE,  intr) | gpio_set_level(pin, 0); }
	if(mode == GPIO_MODEX_OPPH)  { return GPIO_Config(pin, GPIO_MODE_OUTPUT,    GPIO_PULLUP_ENABLE,  GPIO_PULLDOWN_ENABLE,  intr) | gpio_set_level(pin, 1); }
	if(mode == GPIO_MODEX_OODL)  { return GPIO_Config(pin, GPIO_MODE_OUTPUT_OD, GPIO_PULLUP_DISABLE, GPIO_PULLDOWN_DISABLE, intr) | gpio_set_level(pin, 0); }
	if(mode == GPIO_MODEX_OODH)  { return GPIO_Config(pin, GPIO_MODE_OUTPUT_OD, GPIO_PULLUP_DISABLE, GPIO_PULLDOWN_DISABLE, intr) | gpio_set_level(pin, 1); }
	return ESP_ERR_INVALID_ARG;
}

/**
 * 可能的重启原因有：
ESP_RST_UNKNOWN,    //!< Reset reason can not be determined
ESP_RST_POWERON,    //!< Reset due to power-on event
ESP_RST_EXT,        //!< Reset by external pin (not applicable for ESP32)
ESP_RST_SW,         //!< Software reset via esp_restart
ESP_RST_PANIC,      //!< Software reset due to exception/panic
ESP_RST_INT_WDT,    //!< Reset (software or hardware) due to interrupt watchdog
ESP_RST_TASK_WDT,   //!< Reset due to task watchdog
ESP_RST_WDT,        //!< Reset due to other watchdogs
ESP_RST_DEEPSLEEP,  //!< Reset after exiting deep sleep mode
ESP_RST_BROWNOUT,   //!< Brownout reset (software or hardware)
ESP_RST_SDIO,       //!< Reset over SDIO
*/
bool osIsAbnormalReboot() {
	esp_reset_reason_t reason = osGetResetReason();
	switch(reason) {
		case ESP_RST_POWERON:
		case ESP_RST_SW:
		case ESP_RST_DEEPSLEEP:
			return FALSE;
		default:
			return TRUE;
	}
}

/**
 * 获取 EFUSE 中的默认 MAC 地址
 */
esp_err_t osGetDefaultMac(uint8_t mac[6]) {
	esp_efuse_desc_t desc = {
		.efuse_block = EFUSE_BLK0,
		.bit_start = 32,
		.bit_count = 48
	};
	esp_efuse_desc_t *fields[] = { &desc, NULL };

	esp_err_t err = esp_efuse_read_field_blob(fields, mac, 48);
	if(err) { return err; }

	// esp_efuse_read_field_blob() 读出来的 MAC 地址与实际的是字节序是反的，所以需要重新排列
	bytes_reverse(mac, 6);
	return ESP_OK;
}

/// 常用内置硬件接口地址
const Ship2Addr Ship2Addr_NULL  = { .bytes = {Ship2AddrType_NULL} };
const Ship2Addr Ship2Addr_UART0 = { .bytes = {Ship2AddrType_P2P|0x01, 0x00} };
const Ship2Addr Ship2Addr_UART1 = { .bytes = {Ship2AddrType_P2P|0x01, 0x01} };
const Ship2Addr Ship2Addr_UART2 = { .bytes = {Ship2AddrType_P2P|0x01, 0x02} };
const Ship2Addr Ship2Addr_UART3 = { .bytes = {Ship2AddrType_P2P|0x01, 0x03} };
const Ship2Addr Ship2Addr_UART4 = { .bytes = {Ship2AddrType_P2P|0x01, 0x04} };
const Ship2Addr Ship2Addr_UART5 = { .bytes = {Ship2AddrType_P2P|0x01, 0x05} };
const Ship2Addr Ship2Addr_SPI0 	= { .bytes = {Ship2AddrType_P2P|0x01, 0x06} };
const Ship2Addr Ship2Addr_SPI1 	= { .bytes = {Ship2AddrType_P2P|0x01, 0x07} };
const Ship2Addr Ship2Addr_SPI2 	= { .bytes = {Ship2AddrType_P2P|0x01, 0x08} };
const Ship2Addr Ship2Addr_SPI3 	= { .bytes = {Ship2AddrType_P2P|0x01, 0x09} };
const Ship2Addr Ship2Addr_I2C0 	= { .bytes = {Ship2AddrType_P2MP|0x01, 0x00} };
const Ship2Addr Ship2Addr_I2C1 	= { .bytes = {Ship2AddrType_P2MP|0x01, 0x01} };
const Ship2Addr Ship2Addr_I2C2 	= { .bytes = {Ship2AddrType_P2MP|0x01, 0x02} };
const Ship2Addr Ship2Addr_I2C3 	= { .bytes = {Ship2AddrType_P2MP|0x01, 0x03} };

/// 本机地址常量
const Ship2Addr Ship2Addr_P2P    = { .bytes = {Ship2AddrType_P2P|0x00} };

/// 广播地址常量
const Ship2Addr Ship2BroadcastAddr_ALL        = { .bytes = {0xF0} };
const Ship2Addr Ship2BroadcastAddr_ALL_P2P    = { .bytes = {0xF1, Ship2IfType_P2P} };
const Ship2Addr Ship2BroadcastAddr_ALL_P2MP   = { .bytes = {0xF1, Ship2IfType_P2MP} };
const Ship2Addr Ship2BroadcastAddr_ALL_RFComm = { .bytes = {0xF1, Ship2IfType_RFComm} };

const Ship2Addr Ship2BroadcastAddr_P2P    = { .bytes = {Ship2AddrType_P2P|0x00} };
const Ship2Addr Ship2BroadcastAddr_P2MP   = { .bytes = {Ship2AddrType_P2MP|0x04, 0xFF, 0xFF, 0xFF, 0xFF} };
const Ship2Addr Ship2BroadcastAddr_RFComm = { .bytes = {Ship2AddrType_RFComm|0x04, 0xFF, 0xFF, 0xFF, 0xFF} };

const char* Ship2Addr_toString(const Ship2Addr* addr) {
	static char buf[64];
	switch(addr->st.ifType) {
	case Ship2IfType_NULL      : return "NULL";
	case Ship2IfType_P2P   	   : return "P2P";
	case Ship2IfType_P2MP      : snprintf(buf, 64, "P2MP[]"); return buf;
	case Ship2IfType_RFComm    : snprintf(buf, 64, "RFComm[%08X]", ntoh32(addr->rfcomm.devId)); return buf;
	case Ship2IfType_TCP       : return "TCP";
	case Ship2IfType_UDP       : snprintf(buf, 64, "UDP[%s:%d]", ip4_u32_to_str(addr->udp.ipv4, NULL), ntoh16(addr->udp.port)); return buf;
	case Ship2IfType_SPP       : return "SPP"       ;
	case Ship2IfType_BLEBeacon : return "BLEBeacon" ;
	case Ship2IfType_WiFiBeacon: return "WiFiBeacon";
	case Ship2IfType_LoRa      : return "LoRa"      ;
	case Ship2IfType_Zigbee    : return "Zigbee"    ;
	case Ship2IfType_RF433     : return "RF433"     ;
	case Ship2IfType_RF315     : return "RF315"     ;
	case Ship2IfType_IR        : return "IR"        ;
	case Ship2IfType_HXDIR     : return "HXDIR"     ;
	case Ship2IfType_MAX       : return "MAX"       ;
	}
	return buf;
}

bool Ship2Addr_same(const Ship2Addr* addr1, const Ship2Addr* addr2) {
	return memcmp(addr1, addr2, 1 + addr1->st.addrSize) == 0;
}

void Ship2Addr_copy(Ship2Addr* addr1, const Ship2Addr* addr2) {
    memset(addr1, 0, sizeof(Ship2Addr));
    memcpy(addr1, addr2, 1 + addr2->st.addrSize);
}

const char* getRcCodeTypeName(RcCodeType type) {
	switch(type) {
	case RcCodeType_RAW:         return "RAW";
	case RcCodeType_PULSE_INDEX: return "PULSE_INDEX";
	case RcCodeType_BIT:         return "BIT";
	case RcCodeType_HXDIR:       return "HXDIR";
	default: return "UNKNOWN";
	}
}

const char* getRcIfTypeName(RcIfType type) {
	switch(type) {
	case RcIfType_RF315: return "RF315";
	case RcIfType_RF433: return "RF433";
	case RcIfType_IR:    return "IR";
	case RcIfType_HXDIR: return "HXDIR";
	default: return "UNKNOWN";
	}
}

// 初始化 Key-Value 存储
esp_err_t nvs_init() {
	esp_err_t ret = nvs_flash_init();
    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
        RET_ON_ERROR(nvs_flash_erase());
        ret = nvs_flash_init();
    }
    return ret;
}

esp_err_t nvs_blob_erase(const char* ns, const char* name) {
	if(!ns || !name) { return ESP_ERR_INVALID_ARG; }
	esp_err_t err;
	nvs_handle hnvs = 0;
	char lenKey[16] = "#"; strncpy(lenKey+1, name, 15); // 长度字段名

	err = nvs_open(ns, NVS_READWRITE, &hnvs); if(err) { goto error; } 	// 打开存储
	err = nvs_erase_key(hnvs, lenKey);                                  // 删除长度字段
	err = nvs_erase_key(hnvs, name);                                    // 删除数据
	err = nvs_commit(hnvs);

error:
	if(hnvs) { nvs_close(hnvs); }
	return err;
}

esp_err_t nvs_blob_save(const char* ns, const char* name, const void* data, int len) {
	if(!ns || !name || !data || !len) { return ESP_ERR_INVALID_ARG; }
	esp_err_t err;
	nvs_handle hnvs = 0;
	char lenKey[16] = "#"; strncpy(lenKey+1, name, 15); // 长度字段名

	err = nvs_open(ns, NVS_READWRITE, &hnvs); if(err) { goto error; } 	// 打开存储
	err = nvs_set_i32(hnvs, lenKey, len); if(err) { goto error; }		// 保存长度字段
	err = nvs_set_blob(hnvs, name, data, len); if(err) { goto error; }	// 保存数据
	err = nvs_commit(hnvs);

error:
	if(hnvs) { nvs_close(hnvs); }
	return err;
}

esp_err_t nvs_blob_load_into(const char* ns, const char* name, void* data, int len) {
	if(!ns || !name || !data || !len) { return ESP_ERR_INVALID_ARG; }
	esp_err_t err;
	nvs_handle hnvs = 0;
	char lenKey[16] = "#"; strncpy(lenKey+1, name, 15); // 长度字段名
	int32_t len0 = 0;
	size_t len1 = 0;

	err = nvs_open(ns, NVS_READONLY, &hnvs); if(err) { goto error; } 	// 打开存储
	err = nvs_get_i32(hnvs, lenKey, &len0); if(err) { goto error; } 	// 获取长度字段
	if(len0 != len) { err = ESP_ERR_INVALID_SIZE; goto error; }			// 检查长度
	len1 = len0;
	err = nvs_get_blob(hnvs, name, data, &len1); if(err) { goto error; }// 获取数据
	if(len1 != len) { err = ESP_ERR_INVALID_SIZE; goto error; }			// 检查长度

error:
	if(hnvs) { nvs_close(hnvs); }
	return err;
}

void* nvs_blob_load(const char* ns, const char* name, int* len) {
	if(!ns || !name || !len) { return NULL; }
	esp_err_t err;
	nvs_handle hnvs = 0;
	char lenKey[16] = "#"; strncpy(lenKey+1, name, 15); // 长度字段名
	void* data = NULL;
	int32_t len0 = 0;
	size_t size = 0;

	err = nvs_open(ns, NVS_READONLY, &hnvs); if(err) { goto error; } 	// 打开存储
	err = nvs_get_i32(hnvs, lenKey, &len0); if(err) { goto error; } 	// 获取长度字段
	size = len0;
	data = malloc(size); if(!data) { goto error; } 						// 分配数据内存
	err = nvs_get_blob(hnvs, name, data, &size); if(err) { goto error; }// 获取数据
	nvs_close(hnvs);
	*len = size;
	return data;

error:
	if(data) { free(data); *len = 0; }
	if(hnvs) { nvs_close(hnvs); }
	return NULL;
}

int nvs_blob_length(const char* ns, const char* name) {
	if(!ns || !name) { return -1; }
	esp_err_t err;
	nvs_handle hnvs = 0;
	char lenKey[16] = "#"; strncpy(lenKey+1, name, 15); // 长度字段名
	int32_t len = -1;

	err = nvs_open(ns, NVS_READONLY, &hnvs); if(err) { return -1; } 	// 打开存储
	err = nvs_get_i32(hnvs, lenKey, &len);								// 获取长度字段
	nvs_close(hnvs);
	return len;
}
